#include "../include/doublylinklist.h"
#include <stdlib.h>
#include <stdio.h>

Status DoublyLinkListInit( PDoublyLinkList L )
{
    if ( L == NULL ) {
        return PARAMERROR;
    }

    L->header = ( PDoublyLinkNode ) malloc( sizeof( DoublyLinkNode ) );

    if ( L->header == NULL ) {
        return MEMERROR;
    }

    L->header->next = L->header;
    L->header->prior = L->header;

    L->length = 0;

    return OK;
}

Status DoublyLinkListCreate( PDoublyLinkList L,
                             ElemType *pVec,
                             int length )
{
    PDoublyLinkNode pnew = L->header;
    PDoublyLinkNode plast = L->header;
    int nCnt = 0;

    if ( L == NULL ) {
        return PARAMERROR;
    }

    if ( L->length != 0 ) {
        DoublyLinkListClear( L );
    }

    for ( nCnt = 1; nCnt <= length; ++nCnt ) {
        pnew = ( PDoublyLinkNode )malloc( sizeof( DoublyLinkNode ) );
        pnew->elem = pVec[nCnt - 1];

        DoublyLinkListInsertNode( plast, pnew );

        plast = pnew;
    }

    L->length = length;

    return OK;
}

Status DoublyLinkListDeleteElem( PDoublyLinkList L,
                                 int pos,
                                 ElemType *pe )
{
    PDoublyLinkNode pfirst = NULL;
    PDoublyLinkNode prior = NULL;
    Status status = DoublyLinkListGetNode( L, pos, &pfirst );

    if ( OK == status ) {
        *pe = pfirst->elem;
        prior = pfirst->prior;
        prior->next = pfirst->next;
        prior->next->prior = prior;

        free( pfirst );

        --( L->length );
    }

    return status;
}

Status DoublyLinkListClear( PDoublyLinkList L )
{
    PDoublyLinkNode first = L->header->next;
    PDoublyLinkNode destory = NULL;

    if ( L == NULL ) {
        return PARAMERROR;
    }

    while ( first != L->header ) {
        destory = first;
        first = first->next;
        free( destory );
    }

    L->header->next = L->header;
    L->header->prior = L->header;

    L->length = 0;

    return OK;
}

Status DoublyLinkListGetElem( PDoublyLinkList L,
                              int pos,
                              ElemType *e )
{
    PDoublyLinkNode pcur = NULL;
    Status status = DoublyLinkListGetNode( L, pos, &pcur );

    if ( OK == status ) {
        *e = pcur->elem;
    }

    return status;
}

Status DoublyLinkListUnInit( PDoublyLinkList L )
{
    if ( L == NULL ) {
        return PARAMERROR;
    }

    free( L->header );
    L->header = NULL;

    L->length = 0;

    return OK;
}

Status DoublyLinkListSetElem( PDoublyLinkList L,
                              int pos,
                              ElemType e )
{
    PDoublyLinkNode pcur = NULL;
    Status status = DoublyLinkListGetNode( L, pos, &pcur );

    if ( OK == status ) {
        pcur->elem = e;
    }

    return status;
}

Status DoublyLinkListGetNode( PDoublyLinkList L,
                              int pos,
                              PDoublyLinkNode *ppNode )
{
    PDoublyLinkNode pcur = NULL;
    int nCnt = 1;

    if ( L == NULL || pos > L->length || pos < 1 ) {
        return PARAMERROR;
    }

    pcur = L->header->next;

    while ( pos != nCnt ) {
        pcur = pcur->next;
        ++nCnt;
    }

    *ppNode = pcur;

    return OK;
}

void DoublyLinkListTraverse( PDoublyLinkList L, visit pCallBack )
{
    PDoublyLinkNode pcur = L->header->next;

    printf( "[" );

    while ( pcur != L->header ) {
        if ( !pCallBack( &( pcur->elem ) ) ) {
            break;
        }

        if ( pcur->next != L->header ) {
            printf( ", " );
        }

        pcur = pcur->next;
    }

    printf( "]\n" );
}

BOOL DoublyLinkListOutPut( ElemType *e )
{
    if ( e == NULL ) {
        return FALSE;
    }

    printf( "%d", *e );

    return TRUE;
}

Status DoublyLinkListInsertElem( PDoublyLinkList L,
                                 int pos,
                                 ElemType e )
{
    PDoublyLinkNode prior = NULL;
    PDoublyLinkNode pnew = NULL;
    Status status = OK;

    if ( pos > L->length + 1 ) {
        return PARAMERROR;
    }

    status = DoublyLinkListGetNode( L, pos, &prior );

    if ( status == OK ) {
        pnew = ( PDoublyLinkNode )malloc( sizeof( DoublyLinkNode ) );
        pnew->elem = e;

        DoublyLinkListInsertNode( prior, pnew );
        ++( L->length );
    }

    return status;
}

Status DoublyLinkListPushBack( PDoublyLinkList L, ElemType e )
{
    PDoublyLinkNode prior = NULL;
    PDoublyLinkNode pnew = NULL;
    Status status = OK;

    status = DoublyLinkListGetNode( L, L->length, &prior );

    if ( status == OK ) {
        pnew = ( PDoublyLinkNode )malloc( sizeof( DoublyLinkNode ) );
        pnew->elem = e;

        DoublyLinkListInsertNode( prior, pnew );
        ++( L->length );
    }

    return status;
}

void DoublyLinkListInsertNode( PDoublyLinkNode prior,
                               PDoublyLinkNode pnew )
{
    pnew->next = prior->next;
    pnew->next->prior = pnew;

    prior->next = pnew;
    pnew->prior = prior;
}

int DoublyLinkListFindElem( PDoublyLinkList L, ElemType e )
{
    PDoublyLinkNode cur = NULL;
    int nCnt = 1;

    if ( L == NULL || L->length == 0 ) {
        return 0;
    }

    cur = L->header->next;

    while ( L->header != cur ) {
        if ( e == cur->elem ) {
            break;
        } else {
            ++nCnt;
            cur = cur->next;
        }
    }

    if ( nCnt > L->length ) {
        return 0;
    }

    return nCnt;
}

int DoublyLinkListLength( PDoublyLinkList L )
{
    if ( L == NULL ) {
        return 0;
    }

    return L->length;
}

BOOL DoublyLinkListEmpty( PDoublyLinkList L )
{
    if ( L == NULL || L->length == 0 || L->header == NULL ) {
        return TRUE;
    }

    return FALSE;
}

void DoublyLinkListTraverseBack( PDoublyLinkList L, visit pCallBack )
{
    PDoublyLinkNode pcur = L->header->prior;

    printf( "[" );

    while ( pcur != L->header ) {
        if ( !pCallBack( &( pcur->elem ) ) ) {
            break;
        }

        if ( pcur->prior != L->header ) {
            printf( ", " );
        }

        pcur = pcur->prior;
    }

    printf( "]\n" );
}
